package com.nutiteq.location;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Display;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.List;
import javax.microedition.midlet.MIDletStateChangeException;

import com.nutiteq.MapComponent;
import com.nutiteq.components.WgsPoint;
import com.nutiteq.controls.ControlKeys;
import com.nutiteq.helpers.BluetoothGpsBrowser;
import com.nutiteq.listeners.MapListener;
import com.nutiteq.maps.CloudMade;
import com.nutiteq.utils.LogForm;
import com.nutiteq.utils.Utils;

public class GPSCanvas extends Canvas implements MapListener, CommandListener, LocationSourceWaiter {
  private static final int PROVIDER_TEST_SOURCE = 0;
  static final int PROVIDER_LOCATION_API = 1;
  static final int PROVIDER_BLUETOOTH = 2;
  static final int PROVIDER_SE_CELLID = 3;
  static final int PROVIDER_NOKIA_CELLID = 4;
  static final int PROVIDER_AUTOMATIC_NOKIA_CELLID = 5;
  static final int PROVIDER_NOKIA_ERICSSON = 6;

  private final MapComponent mapComponent;
  private boolean initialized;
  private Command exit;
  private Command gpsSelection;

  private List gpsOptions;
  private final Command back = new Command("Back", Command.BACK, 0);
  private final Command select = new Command("Select", Command.OK, 0);
  public Command removeGPS = new Command("Remove marker", Command.ITEM, 0);
  private final Image gpsImage;
  private final Image gpsConnectionLost;
  private LocationSource dataSource;

  public GPSCanvas() {
    mapComponent = new MapComponent("abcdtrial", "Nutiteq", "GPSSample", getWidth(), getHeight(),
        new WgsPoint(24.746704, 59.429013), 10);

    gpsImage = Utils.createImage("/gps_marker.png");
    gpsConnectionLost = Utils.createImage("/gps_connection_lost.png");

    initialize();
  }

  private void initialize() {
    mapComponent.setMapListener(this);

    mapComponent.defineControlKey(ControlKeys.MOVE_UP_KEY, -1);
    mapComponent.defineControlKey(ControlKeys.MOVE_DOWN_KEY, -2);
    mapComponent.defineControlKey(ControlKeys.MOVE_LEFT_KEY, -3);
    mapComponent.defineControlKey(ControlKeys.MOVE_RIGHT_KEY, -4);
    mapComponent.defineControlKey(ControlKeys.SELECT_KEY, -5);
    mapComponent.defineControlKey(ControlKeys.ZOOM_OUT_KEY, Canvas.KEY_NUM1);
    mapComponent.defineControlKey(ControlKeys.ZOOM_IN_KEY, Canvas.KEY_NUM3);
    //MPowerPlayer
    mapComponent.defineControlKey(ControlKeys.MOVE_UP_KEY, 38);
    mapComponent.defineControlKey(ControlKeys.MOVE_DOWN_KEY, 40);
    mapComponent.defineControlKey(ControlKeys.MOVE_LEFT_KEY, 37);
    mapComponent.defineControlKey(ControlKeys.MOVE_RIGHT_KEY, 39);
    mapComponent.defineControlKey(ControlKeys.SELECT_KEY, 10);
    //for motorola
    mapComponent.defineControlKey(ControlKeys.MOVE_UP_KEY, KEY_NUM2);
    mapComponent.defineControlKey(ControlKeys.MOVE_DOWN_KEY, KEY_NUM8);
    mapComponent.defineControlKey(ControlKeys.MOVE_LEFT_KEY, KEY_NUM4);
    mapComponent.defineControlKey(ControlKeys.MOVE_RIGHT_KEY, KEY_NUM6);
    mapComponent.defineControlKey(ControlKeys.SELECT_KEY, KEY_NUM5);

    mapComponent.showZoomLevelIndicator(true);

    if (hasPointerEvents()) {
      mapComponent.showDefaultOnScreenZoomControls();
    } else {
      mapComponent.showDefaultCursor();
    }

    exit = new Command("Exit", Command.EXIT, 0);
    gpsSelection = new Command("Location", Command.ITEM, 0);

    addCommand(exit);
    addCommand(gpsSelection);
    addCommand(LogForm.SHOW_LOG);

    setCommandListener(this);

    mapComponent.startMapping();
    initialized = true;
  }

  protected void paint(final Graphics g) {
    if (!initialized) {
      return;
    }

    mapComponent.paint(g);
    g.setColor(0xFF000000);
    g.setClip(0, 0, getWidth(), getHeight());
    if (dataSource != null && dataSource.getStatus() == LocationSource.STATUS_CONNECTING) {
      g.drawString("Locating...", getWidth(), 0, Graphics.TOP | Graphics.RIGHT);
    } else if (dataSource != null && dataSource.getStatus() == LocationSource.STATUS_CANT_LOCATE) {
      g.drawString("Can't locate", getWidth(), 0, Graphics.TOP | Graphics.RIGHT);
    }
  }

  protected void keyPressed(final int keyCode) {
    if (!initialized) {
      return;
    }

    mapComponent.keyPressed(keyCode);
  }

  protected void keyReleased(final int keyCode) {
    if (!initialized) {
      return;
    }

    mapComponent.keyReleased(keyCode);
  }

  protected void keyRepeated(final int keyCode) {
    if (!initialized) {
      return;
    }

    mapComponent.keyRepeated(keyCode);
  }

  protected void pointerDragged(final int x, final int y) {
    if (!initialized) {
      return;
    }

    mapComponent.pointerDragged(x, y);
  }

  protected void pointerPressed(final int x, final int y) {
    if (!initialized) {
      return;
    }

    mapComponent.pointerPressed(x, y);
  }

  protected void pointerReleased(final int x, final int y) {
    if (!initialized) {
      return;
    }

    mapComponent.pointerReleased(x, y);
  }

  public void mapClicked(final WgsPoint p) {

  }

  public void mapMoved() {

  }

  public void needRepaint(final boolean mapIsComplete) {
    repaint();
  }

  public void commandAction(final Command cmd, final Displayable d) {
    if (cmd == exit) {
      mapComponent.stopMapping();
      try {
        GPSMIDlet.instance.destroyApp(true);
      } catch (final MIDletStateChangeException ignore) {
      }
    } else if (cmd == gpsSelection) {
      gpsOptions = new List("Positioning implementations", List.IMPLICIT);
      gpsOptions.append("Demo GPS", null);
      gpsOptions.append("Internal GPS (JSR179)", null);
      gpsOptions.append("Bluetooth GPS", null);
      gpsOptions.append("SonyEricsson -> Ericsson Labs API", null);
      gpsOptions.append("Nokia -> OpenCellID API", null);
      gpsOptions.append("Automatic Nokia CellID", null);
      gpsOptions.append("Nokia -> Ericsson Labs API", null);
      gpsOptions.addCommand(back);
      gpsOptions.addCommand(select);
      gpsOptions.setCommandListener(this);
      show(gpsOptions);
    } else if (cmd == back) {
      show(this);
    } else if (d == gpsOptions) {
      if (cmd == select || cmd == List.SELECT_COMMAND) {
        switch (gpsOptions.getSelectedIndex()) {
        case PROVIDER_TEST_SOURCE:
          show(new TestSourceSettings(mapComponent, this, gpsImage));
          return;
        case PROVIDER_BLUETOOTH:
          final BluetoothGpsBrowser gpsBrowser = new BluetoothGpsBrowser("Bluetooth GPS", this,
              "Searching...", "No devices found", "Select", "Back");
          show(gpsBrowser);
          return;
        default:
          show(new LibraryGPSSettings(gpsOptions.getSelectedIndex(), mapComponent, this, gpsImage,
              gpsConnectionLost));
          return;
        }
      }
    } else if (cmd == removeGPS) {
      mapComponent.removeLocationSource();
      removeCommand(removeGPS);
    } else if (cmd == LogForm.SHOW_LOG) {
      show(new LogForm(mapComponent, GPSMIDlet.instance, this));
    }
  }

  public void show(final Displayable next) {
    Display.getDisplay(GPSMIDlet.instance).setCurrent(next);
  }

  public void setLocationDataSource(final LocationSource dataSource) {
    this.dataSource = dataSource;
  }

  public void browsingCanceled() {
    show(this);
  }

  public void setLocationSource(final LocationSource locationSource) {
    final LibraryGPSSettings settings = new LibraryGPSSettings(PROVIDER_BLUETOOTH, mapComponent,
        this, gpsImage, gpsConnectionLost);
    settings.setBluetoothStuff(locationSource);
    show(settings);
  }
}
